home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OctaMED Sound Studio 1
/
OctaMED SoundStudio V1.iso
/
soundstudio v1
/
programmers
/
pro8player.a
< prev
next >
Wrap
Text File
|
1996-06-18
|
69KB
|
2,546 lines
;============================================================================
; pro8player.a
; ~~~~~~~~~~~
; $VER: pro8player 7.0 (4.2.1996)
;
; The music player routine for MMD0/MMD1/MMD2 MED/OctaMED
; eight channel modules.
;
; Copyright © 1995-1996 Teijo Kinnunen and RBF Software.
;
; Written by Teijo Kinnunen.
; Comments/questions/bug reports can be sent to:
; Teijo Kinnunen
; Oksantie 19
; FIN-86300 OULAINEN
; FINLAND
; email: Teijo.Kinnunen@oulu.fi
;
; See OctaMED docs for conditions about using these routines.
; Comments/questions about distribution and usage conditions
; should be directed to RBF Software. (Email: rbfsoft@cix.compulink.co.uk)
;
;============================================================================
;****** Feature control ******
;
AUDDEV EQU 1 ;1 = allocate channels using audio.device
CHECK EQU 1 ;1 = do range checkings (track, sample in mem etc.)
IFFMOCT EQU 1 ;1 = play IFF multi-octave samples correctly
HOLD EQU 1 ;1 = handle hold/decay
PLAYMMD0 EQU 1 ;1 = play old MMD0 modules
FASTMEMPLAY EQU 1 ;1 = make FastMemPlay available
;============================================================================
; The MMD structure offsets
mmd_id EQU 0
mmd_modlen EQU 4
mmd_songinfo EQU 8
; these two for MMD2s only!
mmd_psecnum EQU 12
mmd_pseq EQU 14
;
mmd_blockarr EQU 16
mmd_smplarr EQU 24
mmd_expdata EQU 32
mmd_pstate EQU 40 ; <0 = play song, 0 = don't play, >0 = play block
mmd_pblock EQU 42
mmd_pline EQU 44
mmd_pseqnum EQU 46
mmd_actplayline EQU 48
mmd_counter EQU 50
mmd_songsleft EQU 51
; Instrument data
inst_repeat EQU 0
inst_replen EQU 2
inst_midich EQU 4
inst_midipreset EQU 5
inst_svol EQU 6
inst_strans EQU 7
; Audio hardware offsets
ac_ptr EQU $00
ac_len EQU $04
ac_per EQU $06
ac_vol EQU $08
ac_end EQU $0C
ac_rest EQU $10
ac_mask EQU $14
ac_rhw EQU $16
ac_fmp EQU $1A
INCLUDE "medtrkdata.i"
SECTION "text",CODE
IFNE FASTMEMPLAY
rpnewv rts
sdma_fastmem move.w intonmsk-DB(a6),d0
beq.s rpnewv ;a RTS
movem.l a2/a5/d2,-(sp)
move.w d0,d2
lea trackdata8-DB+4(a6),a2
lsr.w #8,d2
movea.l (a2)+,a1
lsr.b #1,d2
bcc.s 2$
movea.l trk_fmp(a1),a1
lea $DFF000,a0
bsr.w _FmpIntHandler
2$ movea.l (a2)+,a1
lsr.b #1,d2
bcc.s 3$
movea.l trk_fmp(a1),a1
lea $DFF000,a0
bsr.w _FmpIntHandler
3$ lsr.b #1,d2
bcc.s 4$
movea.l (a2),a1
movea.l trk_fmp(a1),a1
lea $DFF000,a0
bsr.w _FmpIntHandler
4$ movem.l (sp)+,a2/a5/d2
bsr _Wait1line
move.w intonmsk-DB(a6),d1
move.w d1,INTREQ
move.w dmaonmsk-DB(a6),d0
bset #15,d0
move.w d0,DMACON ;turn on DMA
move.w intonmsk-DB(a6),d1
bset #15,d1
move.w d1,INTENA ;enable interrupts
bra _Wait1line
;FastMemPlay interrupt handler routine
;NOTE: audio buffer length must be divisible by 4!
_FmpIntHandler
move.w fmp_intmask(a1),$9C(a0)
; --- See which buffer is in turn
not.b fmp_whichbuff(a1)
beq.s fih_fillbuff
movea.l fmp_bufferptr2(a1),a5
bra.s fih_fb2
fih_fillbuff movea.l fmp_bufferptr(a1),a5
; --- Set the audio address for the next buffer
fih_fb2 movea.l fmp_audioaddr(a1),a0
move.l a5,ac_ptr(a0) ;new sample pointer
; --- Check whether the channel has something valid to play
tst.b fmp_active(a1)
beq fih_inactive
; --- Load remaining buffer size and sample pointer
moveq #0,d1
move.w fmp_buffsize(a1),d1
move.l fmp_currlen(a1),d0
movea.l fmp_currptr(a1),a0
; --- If the remaining sample data entirely fills the buffer,
; --- do a longword copy
cmp.l d1,d0
bhi.s fih_fill_whole_l
; --- Loop. Subtract the remaining sample sz from rem. buffer sz
fih_loop1 sub.w d0,d1
; --- Copy the remaining bytes of the sample
bra.s 2$
1$ move.b (a0)+,(a5)+
2$ dbra d0,1$
; --- If no repeat, go and clear the rest of the buffer
move.l fmp_repeatptr(a1),d0
beq.s fih_norpt
; --- Load repeat begin pointer to A0
move.l d0,a0
; --- And length in D0
move.l fmp_repeatlen(a1),d0
; --- If buffer was exactly filled, exit
tst.w d1
beq.s fih_exitintr
; --- See whether the buffer could be now filled to the end
; --- (can't use longword copy, because the destination might not be
; --- aligned due to odd loop length)
cmp.l d1,d0
bhi.s fih_fill_whole
bra.s fih_loop1
fih_exitintr move.l d0,fmp_currlen(a1)
move.l a0,fmp_currptr(a1)
rts
fih_fill_whole_l
; --- Subtract copied bytes in advance
sub.l d1,d0
; --- Store the remaining sample length
move.l d0,fmp_currlen(a1)
move.l a0,d0
; --- Make sure the source is really aligned (it might not be, if the
; --- loop was aligned on an even boundary)
btst #0,d0
bne.s fih_fill_nonalign
; --- # of longwords
lsr.w #2,d1
subq.w #1,d1
1$ move.l (a0)+,(a5)+
dbra d1,1$
; --- Also store the new source pointer, and exit..
move.l a0,fmp_currptr(a1)
rts
; --- The same as above, but not a longword copy.
fih_fill_whole sub.l d1,d0
move.l d0,fmp_currlen(a1)
fih_fill_nonalign
subq.w #1,d1
1$ move.b (a0)+,(a5)+
dbra d1,1$
move.l a0,fmp_currptr(a1)
rts
; --- Turn off this interrupt, and Audio DMA
fih_inactive move.w fmp_intmask(a1),d0
move.w d0,INTENA
lsr.w #7,d0
move.w d0,DMACON
rts
; --- Fill the rest of the buffer, and cause the channel to go
; --- inactive when the interrupt occurs the next time
fih_clrloop clr.b (a5)+
fih_norpt dbra d1,fih_clrloop
clr.b fmp_active(a1)
rts
_InitFastMemPlayer
movem.l a5/a6,-(sp)
lea DB,a5
movea.l _module8-DB(a5),a0
movea.l mmd_songinfo(a0),a0
tst.b msng_flags2(a0)
bmi.w ifmp_noaudio ;mixing! don't mess with audio hw..
lea fmpstructs,a0
lea $DFF0B0,a1
move.w _fmp_buffsize8-DB(a5),d0
move.w d0,d1
lsr.w #1,d1
move.w #1<<8,fmp_intmask(a0)
clr.w fmp_whichbuff(a0)
move.l a1,fmp_audioaddr(a0)
move.l #_fmpaudiobuff,fmp_bufferptr(a0)
move.l #_fmpaudiobuff+800,fmp_bufferptr2(a0)
move.w d0,fmp_buffsize(a0)
move.w d1,ac_len(a1)
lea fmp_sizeof(a0),a0
lea $10(a1),a1
move.w #1<<9,fmp_intmask(a0)
clr.w fmp_whichbuff(a0)
move.l a1,fmp_audioaddr(a0)
move.l #_fmpaudiobuff+1600,fmp_bufferptr(a0)
move.l #_fmpaudiobuff+2400,fmp_bufferptr2(a0)
move.w d0,fmp_buffsize(a0)
move.w d1,ac_len(a1)
lea fmp_sizeof(a0),a0
lea $10(a1),a1
move.w #1<<10,fmp_intmask(a0)
clr.w fmp_whichbuff(a0)
move.l a1,fmp_audioaddr(a0)
move.l #_fmpaudiobuff+3200,fmp_bufferptr(a0)
move.l #_fmpaudiobuff+4000,fmp_bufferptr2(a0)
move.w d0,fmp_buffsize(a0)
move.w d1,ac_len(a1)
movea.l 4.w,a6
; channel 0 DMA audio is never used in this routine
;lea fmpinterrupt0-DB(a5),a1
;moveq #7,d0
;jsr -$a2(a6) ;SetIntVector()
lea fmpinterrupt1-DB(a5),a1
moveq #8,d0
jsr -$a2(a6) ;SetIntVector()
lea fmpinterrupt2-DB(a5),a1
moveq #9,d0
jsr -$a2(a6) ;SetIntVector()
lea fmpinterrupt3-DB(a5),a1
moveq #10,d0
jsr -$a2(a6) ;SetIntVector()
moveq #1,d0
move.w d0,_use_fastmem-DB(a5)
ifmp_noaudio movem.l (sp)+,a5/a6
rts
_RemAudioInts: move.l a6,-(sp)
tst.w _use_fastmem
beq.s 1$
move.w #$780,INTENA ;switch audio interrupts off
movea.l 4.w,a6
;suba.l a1,a1
;moveq #7,d0
;jsr -$a2(a6) ;SetIntVector()
suba.l a1,a1
moveq #8,d0
jsr -$a2(a6) ;SetIntVector()
suba.l a1,a1
moveq #9,d0
jsr -$a2(a6) ;SetIntVector()
suba.l a1,a1
moveq #10,d0
jsr -$a2(a6) ;SetIntVector()
clr.w _use_fastmem
1$ move.l (sp)+,a6
rts
ENDC
;**************************************************************************
;*
;* 8 CHANNEL PLAY ROUTINE
;*
;**************************************************************************
; This code does the magic 8 channel thing (mixing).
MAGIC_8TRK MACRO
move.b 0(a3,d6.w),d3
add.l d1,d6
addx.w d0,d6
add.b 0(a4,d7.w),d3
add.l d2,d7
move.b d3,(a1)+
addx.w d0,d7
ENDM
_ChannelO8 clr.w trk_prevper(a5)
movea.l trk_audioaddr(a5),a0
clr.w ac_per(a0)
xco8 rts
_PlayNote8: ;d7(w) = trk #, d1 = note #, d3(w) = instr # a3 = addr of instr
movea.l mmd_smplarr(a2),a0
add.w d3,d3 ;d3 = instr.num << 2
add.w d3,d3
move.l 0(a0,d3.w),d5 ;get address of instrument
IFNE CHECK
beq.s xco8
ENDC
inmem8: add.b msng_playtransp(a4),d1 ;add play transpose
add.b inst_strans(a3),d1 ;and instr. transpose
IFNE CHECK
tst.b inst_midich(a3)
bne.s xco8 ;MIDI
ENDC
clr.b trk_vibroffs(a5) ;clr vibrato offset
move.l d5,a0
subq.b #1,d1
IFNE CHECK
tst.w 4(a0)
bmi.s xco8 ;Synth
ENDC
tlwtst08: tst.b d1
bpl.s notenot2low8
add.b #12,d1 ;note was too low, octave up
bra.s tlwtst08
notenot2low8: cmp.b #62,d1
ble.s endpttest8
sub.b #12,d1 ;note was too high, octave down
endpttest8:
moveq #0,d2
moveq #0,d3
moveq #6,d4 ;skip (stereo+hdr) offset
lea _periodtable+32-DB(a6),a1
move.b trk_finetune(a5),d2 ;finetune value
add.b d2,d2
add.b d2,d2 ;multiply by 4...
ext.w d2 ;extend
movea.l 0(a1,d2.w),a1 ;period table address
move.w 4(a0),d0 ;(Instr hdr in a0)
btst #5,d0
beq.s gid_nostereo
move.b d7,d5
and.b #3,d5
beq.s gid_nostereo ;ch 0/4 = play left (norm.)
cmp.b #3,d5
beq.s gid_nostereo ;also for ch 3/7
add.l (a0),d4 ;play right channel
gid_nostereo
IFNE IFFMOCT
and.w #$F,d0
bne.s gid_notnormal ;note # in d1 (0 - ...)
ENDC
gid_cont_ext move.l a1,trk_periodtbl(a5)
add.b d1,d1
move.w 0(a1,d1.w),d5 ;put period to d5
move.l a0,d0
move.l (a0),d1 ;length
add.l d4,d0 ;skip hdr and stereo
add.l d0,d1 ;sample end pointer
move.w inst_repeat(a3),d2
move.w inst_replen(a3),d3
IFNE IFFMOCT
bra gid_setrept
gid_addtable dc.b 0,6,12,18,24,30
gid_divtable dc.b 31,7,3,15,63,127
gid_notnormal cmp.w #7,d0
blt.s gid_not_ext
suba.w #48,a1
bra.s gid_cont_ext
gid_not_ext move.l d7,-(sp)
moveq #0,d7
move.w d1,d7
divu #12,d7 ;octave #
move.l d7,d5
cmp.w #6,d7 ;if oct > 5, oct = 5
blt.s nohioct
moveq #5,d7
nohioct swap d5 ;note number in this oct (0-11) is in d5
move.l (a0),d1
cmp.w #6,d0
ble.s nounrecit
moveq #6,d0
nounrecit add.b gid_addtable-1(pc,d0.w),d7
move.b gid_divtable-1(pc,d0.w),d0
divu d0,d1 ;get length of the highest octave
swap d1
clr.w d1
swap d1
move.l d1,d0 ;d0 and d1 = length of the 1st oct
move.w inst_repeat(a3),d2
move.w inst_replen(a3),d3
moveq #0,d6
move.b shiftcnt(pc,d7.w),d6
lsl.w d6,d2
lsl.w d6,d3
lsl.w d6,d1
move.b mullencnt(pc,d7.w),d6
mulu d6,d0 ;offset of this oct from 1st oct
add.l a0,d0 ;add base address to offset
add.l d4,d0 ;skip header + stereo
add.l d0,d1
move.l a1,trk_periodtbl(a5)
add.b octstart(pc,d7.w),d5
add.b d5,d5
move.w 0(a1,d5.w),d5
move.l (sp)+,d7
bra.s gid_setrept
shiftcnt: dc.b 4,3,2,1,1,0,2,2,1,1,0,0,1,1,0,0,0,0
dc.b 3,3,2,2,1,0,5,4,3,2,1,0,6,5,4,3,2,1
mullencnt: dc.b 15,7,3,1,1,0,3,3,1,1,0,0,1,1,0,0,0,0
dc.b 7,7,3,3,1,0,31,15,7,3,1,0,63,31,15,7,3,1
octstart: dc.b 12,12,12,12,24,24,0,12,12,24,24,36,0,12,12,24,36,36
dc.b 0,12,12,24,24,24,12,12,12,12,12,12,12,12,12,12,12,12
ENDC
gid_setrept add.l d2,d2
add.l d0,d2 ;rep. start pointer
cmp.w #1,d3
bhi.s gid_noreplen2
moveq #0,d3 ;no repeat
bra.s gid_cont
gid_noreplen2 add.l d3,d3
add.l d2,d3 ;rep. end pointer
gid_cont moveq #0,d4
move.w trk_soffset(a5),d4
add.l d4,d0
cmp.l d0,d1
bhi.s pn_nooffsovf8
sub.l d4,d0
pn_nooffsovf8 movea.l trk_audioaddr(a5),a1 ;base of this channel's regs
move.l d0,(a1) ;put it in ac_ptr
moveq #0,d4
move.b trk_previnstr(a5),d4
lea flags-DB(a6),a0
btst #0,0(a0,d4.w) ;test flags.SSFLG_LOOP
bhi.s repeat8
tst.b trk_split(a5)
beq.s pn8_nosplit0
clr.l ac_rest(a1)
subq.l #1,d1
move.l d1,ac_end(a1)
bra.s retsn18
pn8_nosplit0 sub.l d0,d1
lsr.l #1,d1
move.w d1,ac_len(a1)
tst.w _use_fastmem-DB(a6)
bne.s 1$
move.l #_chipzero,ac_rest(a1)
move.w #1,ac_end(a1)
bra.s retsn18
1$ clr.l ac_rest(a1)
bra.s retsn18
repeat8: tst.b trk_split(a5)
bne.s pn8_split1
move.l d3,d1
sub.l d0,d1
lsr.l #1,d1
move.w d1,ac_len(a1)
move.l d2,ac_rest(a1) ;remember rep. start
sub.l d2,d3
lsr.l #1,d3
move.w d3,ac_end(a1) ;remember rep. length
bra.s retsn18
pn8_split1 move.l d2,ac_rest(a1)
move.l d3,ac_end(a1)
retsn18: move.w d5,ac_per(a1) ;getinsdata puts period to d5
move.w d5,trk_prevper(a5)
retsn28: rts
_IntHandler8: movem.l d2-d7/a2-a4,-(sp)
lea DB,a6
lea trksplit-DB(a6),a2
move.w currchsize2-DB(a6),d4
; ================ 8 channel handling (buffer swap) ======
move.w #1600,d0
not.b whichbuff-DB(a6) ;swap buffer
bne.s usebuff1
tst.b (a2)+
beq.s tnspl0
move.l a1,$a0(a0)
move.w d4,$a4(a0)
tnspl0 lea 1600(a1),a5
tst.b (a2)+
beq.s tnspl1
move.l a5,$b0(a0)
move.w d4,$b4(a0)
tnspl1 adda.w d0,a5
tst.b (a2)+
beq.s tnspl2
move.l a5,$c0(a0)
move.w d4,$c4(a0)
tnspl2 adda.w d0,a5
tst.b (a2)
beq.s buffset
move.l a5,$d0(a0)
move.w d4,$d4(a0)
bra.s buffset
usebuff1 lea 800(a1),a1
tst.b (a2)+
beq.s tnspl0b
move.l a1,$a0(a0)
move.w d4,$a4(a0)
tnspl0b lea 1600(a1),a5
tst.b (a2)+
beq.s tnspl1b
move.l a5,$b0(a0)
move.w d4,$b4(a0)
tnspl1b adda.w d0,a5
tst.b (a2)+
beq.s tnspl2b
move.l a5,$c0(a0)
move.w d4,$c4(a0)
tnspl2b tst.b (a2)
beq.s buffset
adda.w d0,a5
move.l a5,$d0(a0)
move.w d4,$d4(a0)
buffset move.w #1<<7,$9c(a0)
lea tmpvol-DB(a6),a2
move.b (a2)+,$a9(a0)
move.b (a2)+,$b9(a0)
move.b (a2)+,$c9(a0)
move.b (a2),$d9(a0)
tst.b _hq-DB(a6)
beq.s nohq
move.l #2031616,d3 ;124 * 16384
bra.s startfillb
nohq move.l #3719168,d3 ;227 * 16384
; ============== fill buffers ============
startfillb moveq #0,d4 ;mask for DMA
clr.w intonmsk-DB(a6)
lea track0hw-DB(a6),a2
tst.b trksplit-DB(a6)
bne.s tspl0c
bsr.w pushregs
bra.s tnspl0c
tspl0c bsr.s fillbuf
movea.l a5,a1
tnspl0c lea track1hw-DB(a6),a2
tst.b trksplit+1-DB(a6)
bne.s tspl1c
bsr.w pushregs
bra.s tnspl1c
tspl1c bsr.s fillbuf
movea.l a5,a1
tnspl1c lea track2hw-DB(a6),a2
tst.b trksplit+2-DB(a6)
bne.s tspl2c
bsr.w pushregs
bra.s tnspl2c
tspl2c bsr.s fillbuf
movea.l a5,a1
tnspl2c lea track3hw-DB(a6),a2
tst.b trksplit+3-DB(a6)
bne.s tspl3c
bsr.w pushregs
bra.w do_play8
tspl3c bsr.s fillbuf
bra.w do_play8
; =========================================================
;calculate channel A period
fillbuf: move.l d3,d7
move.w ac_per(a2),d6
beq.s setpzero0
move.l d7,d2
divu d6,d2
moveq #0,d1
move.w d2,d1
add.l d1,d1
add.l d1,d1
;get channel A addresses
move.l ac_end(a2),a5
move.l (a2),d0
beq.s setpzero0
chA_dfnd move.l d0,a3 ;a3 = start address, a5 = end address
;calc bytes before end
mulu currchsize-DB(a6),d2
clr.w d2
swap d2
; d2 = # of bytes/fill
add.l a3,d2 ;d2 = end position after this fill
sub.l a5,d2 ;subtract sample end
bmi.s norestart0
move.l ac_rest(a2),d0
beq.s rst0end
move.l d0,(a2)
move.l d0,a3
bra.s norestart0
rst0end clr.l (a2)
setpzero0 lea zerodata-DB(a6),a3
moveq #0,d1
norestart0
;channel B period
move.w SIZE4TRKHW+ac_per(a2),d6
beq.s setpzero0b
divu d6,d7
moveq #0,d2
move.w d7,d2
add.l d2,d2
add.l d2,d2
;channel B addresses
move.l SIZE4TRKHW+ac_end(a2),a5
move.l SIZE4TRKHW(a2),d0
beq.s setpzero0b
move.l d0,a4
mulu currchsize-DB(a6),d7
clr.w d7
swap d7
add.l a4,d7
sub.l a5,d7
bmi.s norestart0b
move.l SIZE4TRKHW+ac_rest(a2),d0
beq.s rst0endb
move.l d0,SIZE4TRKHW(a2)
move.l d0,a4
bra.s norestart0b
rst0endb clr.l SIZE4TRKHW(a2)
setpzero0b lea zerodata-DB(a6),a4
moveq #0,d2
norestart0b moveq #0,d6
moveq #0,d7
moveq #0,d0
move.w d3,-(sp)
swap d1
swap d2
lea 1600(a1),a5 ;get addr. of next buffer
tst.b _hq-DB(a6)
bne.w magic_hq
move.w currchszcnt-DB(a6),d5
do8trkmagic
MAGIC_8TRK ;20 times..
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
dbf d5,do8trkmagic ;do until cnt zero
end8trkmagic swap d6
swap d7
clr.w d6
clr.w d7
swap d6
swap d7
add.l d6,(a2)
add.l d7,SIZE4TRKHW(a2)
move.w (sp)+,d3
rts
; The following code is executed only in HQ-mode
magic_hq move.w currchsize2-DB(a6),d5
lsr.w #1,d5
subq.w #1,d5
dohq8trkmagic ;this runs quite efficiently in a cache
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
MAGIC_8TRK
dbf d5,dohq8trkmagic
bra.s end8trkmagic
_Wait1line: move.l d0,-(sp)
moveq #$79,d0
wl0: move.b $dff007,d1
wl1: cmp.b $dff007,d1
beq.s wl1
dbf d0,wl0
move.l (sp)+,d0
rts
; ========== this channel is not splitted
pushregs move.l ac_rhw(a2),a3 ;address of real hardware
tst.w ac_per(a2)
beq.s pregs_stop
move.w ac_per(a2),ac_per(a3) ;push new period
move.l (a2),d0 ;ac_ptr
beq.s pregs_nonewp
move.w ac_mask(a2),d1
move.w d1,$96(a0) ;stop DMA of curr. channel
or.w d1,d4
clr.l (a2)
IFNE FASTMEMPLAY
tst.w _use_fastmem-DB(a6)
bne.s pregs_fmp
ENDC
move.l d0,(a3)+ ;to real ac_ptr
move.w ac_len(a2),(a3) ;push ac_len
pregs_nonewp lea 800(a1),a1 ;next buffer
rts
pregs_stop move.w ac_mask(a2),d1
move.w d1,$96(a0)
bra.s pregs_nonewp
IFNE FASTMEMPLAY
pregs_fmp move.l a0,-(sp)
movea.l ac_fmp(a2),a0
move.w fmp_intmask(a0),d1
move.w d1,INTENA
or.w d1,intonmsk-DB(a6)
st fmp_active(a0)
move.l d0,(a0)+ ;fmp_currptr
moveq #0,d0
move.w ac_len(a2),d0
add.l d0,d0
move.l d0,(a0)+ ;fmp_currlen
move.l ac_rest(a2),(a0)+ ;fmp_rept
move.l ac_end(a2),d0
sub.l ac_rest(a2),d0
move.l d0,(a0) ;fmp_repeatlen
move.l (sp)+,a0
bra.s pregs_nonewp
ENDC
; ========== should we start DMA of non-splitted channels?
do_play8_fm move.w d4,dmaonmsk-DB(a6)
bsr.w sdma_fastmem
bra.s do_play8_b
do_play8 tst.w d4
beq.s do_play8_b ;no.
tst.w _use_fastmem-DB(a6)
bne.s do_play8_fm
bsr.w _Wait1line
bset #15,d4
move.w d4,$96(a0)
bsr.w _Wait1line
lsr.b #1,d4
bcc.s plr_nos8dma0
move.l track0hw+ac_rest-DB(a6),$a0(a0)
move.w track0hw+ac_end-DB(a6),$a4(a0)
plr_nos8dma0 lsr.b #1,d4
bcc.s plr_nos8dma1
move.l track1hw+ac_rest-DB(a6),$b0(a0)
move.w track1hw+ac_end-DB(a6),$b4(a0)
plr_nos8dma1 lsr.b #1,d4
bcc.s plr_nos8dma2
move.l track2hw+ac_rest-DB(a6),$c0(a0)
move.w track2hw+ac_end-DB(a6),$c4(a0)
plr_nos8dma2 lsr.b #1,d4
bcc.s do_play8_b
move.l track3hw+ac_rest-DB(a6),$d0(a0)
move.w track3hw+ac_end-DB(a6),$d4(a0)
; ========== player starts here...
do_play8_b movea.l _module8-DB(a6),a2
move.l a2,d0
beq.w plr_exit
move.l mmd_songinfo(a2),a4
moveq #0,d3
lea mmd_counter(a2),a0
move.b (a0),d3
addq.b #1,d3
cmp.b msng_tempo2(a4),d3
bge.s plr_pnewnote8 ;play new note
move.b d3,(a0)
bra.w nonewnote ;do just fx
; --- new note!! first get address of current block
plr_pnewnote8: clr.b (a0)
tst.w blkdelay-DB(a6)
beq.s plr_noblkdelay8
subq.w #1,blkdelay-DB(a6)
bne.w nonewnote
; -------- GET ADDRESS OF NOTE DATA --------------------------------------
plr_noblkdelay8 move.w mmd_pblock(a2),d0
bsr.w GetNoteDataAddr
moveq #0,d7 ;number of track
moveq #0,d4
IFNE PLAYMMD0
cmp.b #'1',3(a2)
sge d5 ;d5 set -> >= MMD1
ENDC
lea trackdata8-DB(a6),a1
; -------- TRACK LOOP (FOR EACH TRACK) -----------------------------------
plr_loop0: movea.l (a1)+,a5 ;get address of this track's struct
; ---------------- get the note numbers
moveq #0,d3
IFNE PLAYMMD0
tst.b d5
bne.s plr_mmd1_1
move.b (a3)+,d0
move.b (a3),d3
addq.l #2,a3
lsr.b #4,d3
bclr #7,d0
beq.s plr_bseti4
bset #4,d3
plr_bseti4 bclr #6,d0
beq.s plr_bseti5
bset #5,d3
plr_bseti5 move.b d0,trk_currnote(a5)
beq.s plr_nngok
move.b d0,(a5)
bra.s plr_nngok
plr_mmd1_1
ENDC
move.b (a3)+,d0 ;get the number of this note
bpl.s plr_nothinote
moveq #0,d0
plr_nothinote move.b d0,trk_currnote(a5)
beq.s plr_nosetprevn
move.b d0,(a5)
plr_nosetprevn move.b (a3),d3 ;instrument number
addq.l #3,a3 ;adv. to next track
; ---------------- check if there's an instrument number
plr_nngok clr.b trk_fxtype(a5)
and.w #$3F,d3
beq.s noinstnum
; ---------------- finally, save the number
subq.b #1,d3
move.b d3,trk_previnstr(a5) ;remember instr. number!
; ---------------- get the pointer of data's of this sample in Song-struct
move.w d3,d1
asl.w #3,d3
lea 0(a4,d3.w),a0 ;a0 contains now address of it
move.l a0,trk_previnstra(a5)
move.b inst_strans(a0),trk_stransp(a5)
; ---------------- set volume to 64
movea.l trk_audioaddr(a5),a0
movea.l ac_vol(a0),a0 ;ptr to volume hardware register
moveq #64,d0
move.b d0,(a0)
move.b d0,trk_prevvol(a5)
; ---------------- remember some values of this instrument
lea holdvals-DB(a6),a0
adda.w d1,a0
IFNE HOLD
move.b (a0),trk_inithold(a5) ;hold
ENDC
move.b 63(a0),trk_finetune(a5) ;finetune
; ---------------- remember transpose
clr.w trk_soffset(a5) ;sample offset
clr.b trk_miscflags(a5) ;misc.
noinstnum addq.w #1,d7
cmp.w numtracks-DB(a6),d7
blt plr_loop0
bsr.w DoPreFXLoop
; -------- NOTE PLAYING LOOP ---------------------------------------------
moveq #0,d7
lea trackdata8-DB(a6),a1
plr_loop2 movea.l (a1)+,a5
tst.b trk_fxtype(a5)
bne.s plr_loop2_end
move.b trk_currnote(a5),d1
beq.s plr_loop2_end
; ---------------- play
move.l a1,-(sp)
ext.w d1
moveq #0,d3
move.b trk_previnstr(a5),d3 ;instr #
movea.l trk_previnstra(a5),a3 ;instr data address
move.b trk_inithold(a5),trk_noteoffcnt(a5) ;initialize hold
bne.s plr_nohold0 ;not 0 -> OK
st trk_noteoffcnt(a5) ;0 -> hold = 0xff (-1)
; ---------------- and finally:
plr_nohold0 bsr _PlayNote8 ;play it
move.l (sp)+,a1
plr_loop2_end addq.w #1,d7
cmp.w numtracks-DB(a6),d7
blt.s plr_loop2
; -------- THE REST... ---------------------------------------------------
bsr.s AdvSngPtr
nonewnote bsr.w DoFX
plr_exit movem.l (sp)+,d2-d7/a2-a4
moveq #1,d0
rts
AdvSngPtr move.l mmd_pblock(a2),fxplineblk-DB(a6) ;store pline/block for fx
move.w nextblockline-DB(a6),d1
beq.s plr_advlinenum
clr.w nextblockline-DB(a6)
subq.w #1,d1
bra.s plr_linenumset
plr_advlinenum move.w mmd_pline(a2),d1 ;get current line #
addq.w #1,d1 ;advance line number
plr_linenumset cmp.w numlines-DB(a6),d1 ;advance block?
bhi.s plr_chgblock ;yes.
tst.b nextblock-DB(a6) ;command F00/1Dxx?
beq.w plr_nochgblock ;no, don't change block
; -------- CHANGE BLOCK? -------------------------------------------------
plr_chgblock tst.b nxtnoclrln-DB(a6)
bne.s plr_noclrln
moveq #0,d1 ;clear line number
plr_noclrln tst.w mmd_pstate(a2) ;play block or play song
bpl.w plr_nonewseq ;play block only...
cmp.b #'2',3(a2) ;MMD2?
bcs.s plr_noMMD2_0
; ********* BELOW CODE FOR MMD2 ONLY ************************************
; -------- CHANGE SEQUENCE -----------------------------------------------
plr_skipseq move.w mmd_pseq(a2),d0 ;actually stored as << 2
movea.l msng_pseqs(a4),a1 ;ptr to playseqs
movea.l 0(a1,d0.w),a0 ;a0 = ptr to curr PlaySeq
move.w mmd_pseqnum(a2),d0 ;get play sequence number
tst.b nextblock-DB(a6)
bmi.s plr_noadvseq ;Bxx sets nextblock to -1
addq.w #1,d0 ;advance sequence number
plr_noadvseq cmp.w 40(a0),d0 ;is this the highest seq number??
blt.s plr_notagain ;no.
; -------- CHANGE SECTION ------------------------------------------------
move.w mmd_psecnum(a2),d0 ;get section number
addq.w #1,d0 ;increase..
cmp.w msng_songlen(a4),d0 ;highest section?
blt.s plr_nohisec
moveq #0,d0 ;yes.
plr_nohisec move.w d0,mmd_psecnum(a2) ;push back.
add.w d0,d0
movea.l msng_sections(a4),a0 ;section table
move.w 0(a0,d0.w),d0 ;new playseqlist number
add.w d0,d0
add.w d0,d0
move.w d0,mmd_pseq(a2)
movea.l 0(a1,d0.w),a0 ;a0 = ptr to new PlaySeq
moveq #0,d0 ;playseq OFFSET = 0
; -------- FETCH BLOCK NUMBER FROM SEQUENCE ------------------------------
plr_notagain move.w d0,mmd_pseqnum(a2) ;remember new playseq pos
add.w d0,d0
move.w 42(a0,d0.w),d0 ;get number of the block
bpl.s plr_changeblk ;neg. values for future expansion
bra.s plr_skipseq ;(skip them)
; ********* BELOW CODE FOR MMD0/MMD1 ONLY *******************************
plr_noMMD2_0 move.w mmd_pseqnum(a2),d0 ;get play sequence number
tst.b nextblock-DB(a6)
bmi.s plr_noadvseq_b ;Bxx sets nextblock to -1
addq.w #1,d0 ;advance sequence number
plr_noadvseq_b cmp.w msng_songlen(a4),d0 ;is this the highest seq number??
blt.s plr_notagain_b ;no.
moveq #0,d0 ;yes: restart song
plr_notagain_b move.b d0,mmd_pseqnum+1(a2) ;remember new playseq-#
lea msng_playseq(a4),a0 ;offset of sequence table
move.b 0(a0,d0.w),d0 ;get number of the block
; ********* BELOW CODE FOR BOTH FORMATS *********************************
plr_changeblk
IFNE CHECK
cmp.w msng_numblocks(a4),d0 ;beyond last block??
blt.s plr_nolstblk ;no..
moveq #0,d0 ;play block 0
ENDC
plr_nolstblk move.w d0,mmd_pblock(a2) ;store block number
plr_nonewseq clr.w nextblock-DB(a6) ;clear this if F00 set it
; ------------------------------------------------------------------------
plr_nochgblock move.w d1,mmd_pline(a2) ;set new line number
IFNE HOLD
lea trackdata8-DB(a6),a5
move.w mmd_pblock(a2),d0 ;pblock
bsr.w GetBlockAddr
move.w mmd_pline(a2),d0 ;play line
move.b msng_tempo2(a4),d3 ;interrupts/note
IFNE PLAYMMD0
cmp.b #'1',3(a2)
bge.s plr_mmd1_2
move.b (a0),d7 ;# of tracks
move.w d0,d1
add.w d0,d0 ;d0 * 2
add.w d1,d0 ;+ d0 = d0 * 3
mulu d7,d0
lea 2(a0,d0.w),a3
subq.b #1,d7
plr_chkholdb movea.l (a5)+,a1 ;track data
tst.b trk_noteoffcnt(a1) ;hold??
bmi.s plr_holdendb ;no.
move.b (a3),d1 ;get the 1st byte..
bne.s plr_hold1b
move.b 1(a3),d1
and.b #$f0,d1
beq.s plr_holdendb ;don't hold
bra.s plr_hold2b
plr_hold1b and.b #$3f,d1 ;note??
beq.s plr_hold2b ;no, cont hold..
move.b 1(a3),d1
and.b #$0f,d1 ;get cmd
subq.b #3,d1 ;is there command 3 (slide)
bne.s plr_holdendb ;no -> end holding
plr_hold2b add.b d3,trk_noteoffcnt(a1) ;continue holding...
plr_holdendb addq.l #3,a3 ;next note
dbf d7,plr_chkholdb
rts
plr_mmd1_2
ENDC
move.w (a0),d7 ;# of tracks
add.w d0,d0
add.w d0,d0 ;d0 = d0 * 4
mulu d7,d0
lea 8(a0,d0.l),a3
subq.b #1,d7
plr_chkhold movea.l (a5)+,a1 ;track data
tst.b trk_noteoffcnt(a1) ;hold??
bmi.s plr_holdend ;no.
move.b (a3),d1 ;get the 1st byte..
bne.s plr_hold1
move.b 1(a3),d0
and.b #$3F,d0
beq.s plr_holdend ;don't hold
bra.s plr_hold2
plr_hold1 and.b #$7f,d1 ;note??
beq.s plr_hold2 ;no, cont hold..
move.b 2(a3),d1
subq.b #3,d1 ;is there command 3 (slide)
bne.s plr_holdend ;no -> end holding
plr_hold2 add.b d3,trk_noteoffcnt(a1) ;continue holding...
plr_holdend addq.l #4,a3 ;next note
dbf d7,plr_chkhold
ENDC
rts
; *******************************************************************
; DoPreFXLoop: Loop and call DoPreFX
; *******************************************************************
DoPreFXLoop:
; -------- PRE-FX COMMAND HANDLING LOOP ----------------------------------
moveq #0,d5 ;command page count
plr_loop1 move.w mmd_pblock(a2),d0
bsr.w GetBlockAddr
move.w d5,d1
move.w mmd_pline(a2),d2
bsr.w GetCmdPointer
movea.l a0,a3
moveq #0,d7 ;clear track count
lea trackdata8-DB(a6),a1
plr_loop1_1 movea.l (a1)+,a5
move.b (a3),d0 ;command #
beq.s plr_loop1_end
moveq #0,d4
move.b 1(a3),d4 ;data byte
IFNE PLAYMMD0
cmp.b #3,d6 ;if adv == 3 -> MMD0
bne.s doprefx_mmd12mask
and.w #$0F,d0
bra.s doprefx_mmd0maskd
doprefx_mmd12mask
ENDC
and.w #$1F,d0
doprefx_mmd0maskd
bsr.s DoPreFX
or.b d0,trk_fxtype(a5)
plr_loop1_end adda.w d6,a3 ;next track...
addq.w #1,d7
cmp.w numtracks-DB(a6),d7
blt.s plr_loop1_1
addq.w #1,d5
cmp.w numpages-DB(a6),d5
bls.s plr_loop1
rts
; *******************************************************************
; DoPreFX: Perform effects that must be handled before note playing
; *******************************************************************
; args: a6 = DB d0 = command number (w)
; a5 = track data d5 = note number
; a4 = song d4 = data
; d7 = track #
; returns: d0 = 0: play - d0 = 1: don't play
rtplay MACRO
moveq #0,d0
rts
ENDM
rtnoplay MACRO
moveq #1,d0
rts
ENDM
DoPreFX: add.b d0,d0 ;* 2
move.w f_table(pc,d0.w),d0
jmp fst(pc,d0.w)
f_table dc.w fx-fst,fx-fst,fx-fst,f_03-fst,fx-fst,fx-fst,fx-fst,fx-fst
dc.w f_08-fst,f_09-fst,fx-fst,f_0b-fst,f_0c-fst,fx-fst,fx-fst,f_0f-fst
dc.w fx-fst,fx-fst,fx-fst,fx-fst,fx-fst,f_15-fst,f_16-fst,fx-fst
dc.w fx-fst,f_19-fst,fx-fst,fx-fst,fx-fst,f_1d-fst,f_1e-fst,f_1f-fst
fst
; ---------------- tempo (F)
f_0f tst.b d4 ;test effect qual..
beq fx0fchgblck ;if effect qualifier (last 2 #'s)..
cmp.b #$f0,d4 ;..is zero, go to next block
bhi.s fx0fspecial ;if it's F1-FF something special
; ---------------- just an ordinary "change tempo"-request
moveq #0,d0 ;will happen!!!
move.b d4,d0
bsr _SetTempo ;change The Tempo
fx rtplay
; ---------------- no, it was FFx, something special will happen!!
fx0fspecial: cmp.b #$f2,d4
beq.s f_1f
cmp.b #$f4,d4
beq.s f_1f
cmp.b #$f5,d4
bne.s isfxfe
; ---------------- FF2 (or 1Fxx)
f_1f
IFNE HOLD
move.b trk_inithold(a5),trk_noteoffcnt(a5) ;initialize hold
bne.s f_1frts ;not 0 -> OK
st trk_noteoffcnt(a5) ;0 -> hold = 0xff (-1)
ENDC
f_1frts rtnoplay
isfxfe: cmp.b #$fe,d4
bne.s notcmdfe
; ---------------- it was FFE, stop playing
clr.w mmd_pstate(a2)
bsr.w _End8Play
addq.l #8,sp ;2 subroutine levels
bra.w plr_exit
f_ffe_no8 rtplay
notcmdfe: cmp.b #$fd,d4 ;change period
bne.s isfxff
; ---------------- FFD, change the period, don't replay the note
move.l trk_periodtbl(a5),d1 ;period table
beq.s f_1frts
movea.l d1,a0
move.b trk_currnote(a5),d0
subq.b #1,d0 ;sub 1 to make "real" note number
IFNE CHECK
bmi.s f_1frts
ENDC
add.b msng_playtransp(a4),d0
add.b trk_stransp(a5),d0
add.w d0,d0
bmi.s f_1frts
move.w 0(a0,d0.w),trk_prevper(a5) ;get & push the period
rtnoplay
isfxff: cmp.b #$ff,d4 ;note off??
bne.s f_ff_rts
bsr.w _ChannelO8
f_ff_rts rtplay
; ---------------- F00, called Pattern Break in ST
fx0fchgblck: move.b #1,nextblock-DB(a6)
bra.s f_ff_rts
; ---------------- change volume
f_0c btst #4,msng_flags(a4) ;look at flags
bne.s volhex8
move.b d4,d1 ;get again
lsr.b #4,d4 ;get number from left
mulu #10,d4 ;number of tens
and.b #$0f,d1 ;this time don't get tens
add.b d1,d4 ;add them
volhex8
IFNE CHECK
cmp.b #64,d4
bhi.s go_nocmd8
ENDC
movea.l trk_audioaddr(a5),a0
movea.l ac_vol(a0),a0
move.b d4,(a0)
go_nocmd8 rtplay
; ---------------- tempo2 change??
f_09
IFNE CHECK
and.b #$1F,d4
bne.s fx9chk
moveq #$20,d4
ENDC
fx9chk: move.b d4,msng_tempo2(a4)
f_09_rts rtplay
; ---------------- block delay
f_1e tst.w blkdelay-DB(a6)
bne.s f_1e_rts
addq.w #1,d4
move.w d4,blkdelay-DB(a6)
f_1e_rts rtplay
; ---------------- finetune
f_15
IFNE CHECK
cmp.b #7,d4
bgt.s f_15_rts
cmp.b #-8,d4
blt.s f_15_rts
ENDC
move.b d4,trk_finetune(a5)
f_15_rts rtplay
; ---------------- repeat loop
f_16 tst.b d4
bne.s plr_dorpt
move.w mmd_pline(a2),rptline-DB(a6)
bra.s f_16_rts
plr_dorpt tst.w rptcounter-DB(a6)
beq.s plr_newrpt
subq.w #1,rptcounter-DB(a6)
beq.s f_16_rts
bra.s plr_setrptline
plr_newrpt move.b d4,rptcounter+1-DB(a6)
plr_setrptline move.w rptline-DB(a6),d0
addq.w #1,d0
move.w d0,nextblockline-DB(a6)
f_16_rts rtplay
; ---------------- note off time set??
f_08
IFNE HOLD
and.b #$0f,d4
move.b d4,trk_inithold(a5) ;right = hold
ENDC
rtplay
; ---------------- sample begin offset
f_19 lsl.w #8,d4
move.w d4,trk_soffset(a5)
f_19_rts rtplay
; ---------------- cmd Bxx, "position jump"
f_0b
IFNE CHECK
cmp.b #'2',3(a2)
bcc.s chk0b_mmd2
cmp.w msng_songlen(a4),d4
bhi.s f_0b_rts
bra.s chk0b_end
chk0b_mmd2 move.w mmd_pseq(a2),d0 ;get seq number
movea.l msng_pseqs(a4),a0 ;ptr to playseqs
movea.l 0(a0,d0.w),a0 ;a0 = ptr to curr PlaySeq
cmp.w 40(a0),d4 ;test song length
bhi.s f_0b_rts
chk0b_end
ENDC
move.w d4,mmd_pseqnum(a2)
st nextblock-DB(a6) ; = 1
f_0b_rts rtplay
; ---------------- cmd 1Dxx, jump to next seq, line # specified
f_1d move.w #$1ff,nextblock-DB(a6)
addq.w #1,d4
move.w d4,nextblockline-DB(a6)
rtplay
; ---------------- try portamento (3)
f_03 moveq #0,d0
move.b trk_currnote(a5),d0
subq.b #1,d0 ;subtract note number
bmi.s plr_setfx3spd ;0 -> set new speed
move.l trk_periodtbl(a5),d1
beq.s f_03_rts
movea.l d1,a0
add.b msng_playtransp(a4),d0 ;play transpose
add.b trk_stransp(a5),d0 ;and instrument transpose
bmi.s f_03_rts ;again.. too low
add.w d0,d0
move.w 0(a0,d0.w),trk_porttrgper(a5) ;period of this note is the target
plr_setfx3spd: tst.b d4 ;qual??
beq.s f_03_rts ;0 -> do nothing
move.b d4,trk_prevportspd(a5) ;store speed
f_03_rts rtnoplay
; *******************************************************************
; DoFX: Handle effects, hold/fade etc.
; *******************************************************************
DoFX moveq #0,d3
move.b mmd_counter(a2),d3
IFNE HOLD
lea trackdata8-DB(a6),a1
; Loop 1: Hold/Fade handling
moveq #0,d7 ;clear track count
dofx_loop1 movea.l (a1)+,a5
; *******************************************************************
; HoldAndFade: Handle hold/fade
; *******************************************************************
; args: a5 = track data
; a6 = DB
; d7 = track #
; scratches: d0, d1, a0, a1
HoldAndFade tst.b trk_noteoffcnt(a5)
bmi.s plr_haf_dofx
subq.b #1,trk_noteoffcnt(a5)
bpl.s plr_haf_dofx
bsr.w _ChannelO8 ;hold time expired
plr_haf_dofx addq.w #1,d7
cmp.w numtracks-DB(a6),d7
blt.s dofx_loop1
ENDC
; Loop 2: Track command handling
moveq #0,d5 ;command page count
dofx_loop2 move.w fxplineblk-DB(a6),d0
bsr.w GetBlockAddr
movea.l a0,a3
IFNE PLAYMMD0
cmp.b #'1',3(a2)
bge.s dofx_sbd_nommd0
bsr.w StoreBlkDimsMMD0
bra.s dofx_sbd_mmd0
dofx_sbd_nommd0
ENDC
bsr.w StoreBlockDims
dofx_sbd_mmd0 move.w d5,d1
move.w fxplineblk+2-DB(a6),d2
movea.l a3,a0
bsr.s GetCmdPointer
movea.l a0,a3
moveq #0,d7 ;clear track count
lea trackdata8-DB(a6),a1
dofx_loop2_1 movea.l (a1)+,a5
moveq #0,d4
move.b (a3),d0 ;command #
move.b 1(a3),d4 ;data byte
IFNE PLAYMMD0
cmp.b #3,d6 ;if adv == 3 -> MMD0
bne.s dofx_mmd12mask
and.w #$0F,d0
bra.s dofx_mmd0maskd
dofx_mmd12mask
ENDC
and.w #$1F,d0
dofx_mmd0maskd bsr.w ChannelFX
dofx_lend2_1 adda.w d6,a3 ;next track...
addq.w #1,d7
cmp.w numtracks-DB(a6),d7
blt.s dofx_loop2_1
addq.w #1,d5
cmp.w numpages-DB(a6),d5
bls.s dofx_loop2
; Loop 3: Updating audio hardware
moveq #0,d7 ;clear track count
lea trackdata8-DB(a6),a1
dofx_loop3 movea.l (a1)+,a5
; *******************************************************************
; UpdatePerVol: Update audio registers (period & volume) after FX
; *******************************************************************
UpdatePerVol move.w trk_prevper(a5),d1
add.w trk_vibradjust(a5),d1
movea.l trk_audioaddr(a5),a0
sub.w trk_arpadjust(a5),d1
clr.l trk_vibradjust(a5) ;clr both adjusts
move.w d1,ac_per(a0)
dofx_lend3 addq.w #1,d7
cmp.w numtracks-DB(a6),d7
blt.s dofx_loop3
rts
; *******************************************************************
; GetCmdPointer: Return command pointer for track 0
; *******************************************************************
; args: a0 = block pointer
; d1 = page number
; d2 = line number
; a2 = module
; result: a0 = command pointer (i.e. trk 0 note + 2)
; d6 = track advance (bytes)
; scratches: d0, d1, d2, a0
; Note: no num_pages check! If numpages > 0 it can be assumed that
; extra pages exist.
GetCmdPointer
IFNE PLAYMMD0
cmp.b #'1',3(a2)
blt.s GetCmdPtrMMD0
ENDC
mulu (a0),d2 ;d2 = line # * numtracks
add.l d2,d2 ;d2 *= 2...
subq.w #1,d1
bmi.s gcp_page0
movea.l 4(a0),a0
movea.l 12(a0),a0
add.w d1,d1
add.w d1,d1
movea.l 4(a0,d1.w),a0 ;command data
adda.l d2,a0
moveq #2,d6
rts
gcp_page0 add.l d2,d2 ;d2 *= 4
lea 10(a0,d2.l),a0 ;offs: 4 = header, 2 = note
moveq #4,d6 ;track advance (bytes)
rts
IFNE PLAYMMD0
GetCmdPtrMMD0 moveq #0,d0
move.b (a0),d0 ;get numtracks
mulu d0,d2 ;line # * numtracks
move.w d2,d0
add.w d2,d2
add.w d0,d2 ; *= 3...
lea 3(a0,d2.l),a0 ;offs: 2 = header, 1 = note
moveq #3,d6
rts
ENDC
; *******************************************************************
; GetBlockAddr: Return pointer to block
; *******************************************************************
; args: d0 = block number
; result: a0 = block pointer
; scratches: d0, a0
GetBlockAddr movea.l mmd_blockarr(a2),a0
add.w d0,d0
add.w d0,d0
movea.l 0(a0,d0.w),a0
rts
; *******************************************************************
; GetNoteDataAddr: Check & return addr. of current note
; *******************************************************************
;args: d0 = pblock a6 = DB
;returns: a3 = address
;scratches: d0, a0, d1
GetNoteDataAddr bsr.w GetBlockAddr
movea.l a0,a3
IFNE PLAYMMD0
cmp.b #'1',3(a2)
blt.s GetNDAddrMMD0
ENDC
bsr.w StoreBlockDims
move.w numlines-DB(a6),d1
move.w mmd_pline(a2),d0
cmp.w d1,d0 ;check if block end exceeded...
bls.s plr_nolinex
move.w d1,d0
plr_nolinex add.w d0,d0
add.w d0,d0 ;d0 = d0 * 4
mulu (a3),d0
lea 8(a3,d0.l),a3 ;address of current note
rts
IFNE PLAYMMD0
GetNDAddrMMD0 bsr.w StoreBlkDimsMMD0
move.w numlines-DB(a6),d1
move.w mmd_pline(a2),d0
cmp.w d1,d0 ;check if block end exceeded...
bls.s plr_nolinex2
move.w d1,d0
plr_nolinex2 move.w d0,d1
add.w d0,d0
add.w d1,d0 ;d0 = d0 * 3
moveq #0,d1
move.b (a3),d1 ;numtracks
mulu d1,d0
lea 2(a3,d0.l),a3 ;address of current note
rts
ENDC
; *******************************************************************
; StoreBlockDims: Store block dimensions
; *******************************************************************
; args: a0 = block ptr, a6 = DB
StoreBlockDims move.w (a0)+,d0
cmp.w #8,d0
ble.s sbd_lt8
moveq #8,d0
sbd_lt8 move.w d0,numtracks-DB(a6) ;numtracks & lines
move.w (a0)+,numlines-DB(a6)
tst.l (a0) :BlockInfo
beq.s sbd_1page
movea.l (a0),a0
move.l 12(a0),d0 ;BlockInfo.pagetable
beq.s sbd_1page
movea.l d0,a0
move.w (a0),numpages-DB(a6) ;num_pages
rts
sbd_1page clr.w numpages-DB(a6)
rts
IFNE PLAYMMD0
StoreBlkDimsMMD0
clr.w numpages-DB(a6)
moveq #0,d0
move.b (a0)+,d0 ;numtracks
cmp.w #8,d0
ble.s sbd_lt8_2
moveq #8,d0
sbd_lt8_2 move.w d0,numtracks-DB(a6)
move.b (a0),d0 ;numlines
move.w d0,numlines-DB(a6)
rts
ENDC
; *******************************************************************
; ChannelFX: Do an effect on a channel
; *******************************************************************
;args: d3 = counter
; a4 = song struct d4 = command qual (long, byte used)
; a5 = track data ptr
; a6 = DB d0 = command (long, byte used)
; d7 = track (channel) number
;scratches: d0, d1, d4, a0
ChannelFX add.b d0,d0 ;* 2
move.w fx_table(pc,d0.w),d0
jmp fxs(pc,d0.w)
fx_table dc.w fx_00-fxs,fx_01-fxs,fx_02-fxs,fx_03-fxs,fx_04-fxs
dc.w fx_05-fxs,fx_06-fxs,fx_07-fxs,fx_xx-fxs,fx_xx-fxs
dc.w fx_0a-fxs,fx_xx-fxs,fx_xx-fxs,fx_0d-fxs,fx_xx-fxs
dc.w fx_0f-fxs
dc.w fx_xx-fxs,fx_11-fxs,fx_12-fxs,fx_13-fxs,fx_14-fxs
dc.w fx_xx-fxs,fx_xx-fxs,fx_xx-fxs,fx_18-fxs,fx_xx-fxs
dc.w fx_1a-fxs,fx_1b-fxs,fx_xx-fxs,fx_xx-fxs,fx_xx-fxs
dc.w fx_1f-fxs
fxs:
; **************************************** Effect 01 ******
fx_01 tst.b d3
bne.s fx_01nocnt0
btst #5,msng_flags(a4) ;FLAG_STSLIDE??
bne.s fx_01rts
fx_01nocnt0 move.w trk_prevper(a5),d0
sub.w d4,d0
cmp.w #113,d0
bge.s fx_01noovf
move.w #113,d0
fx_01noovf move.w d0,trk_prevper(a5)
fx_xx ;fx_xx is just a RTS
fx_01rts rts
; **************************************** Effect 11 ******
fx_11 tst.b d3
bne.s fx_11rts
sub.w d4,trk_prevper(a5)
fx_11rts rts
; **************************************** Effect 02 ******
fx_02 tst.b d3
bne.s fx_02nocnt0
btst #5,msng_flags(a4)
bne.s fx_02rts
fx_02nocnt0 add.w d4,trk_prevper(a5)
fx_02rts rts
; **************************************** Effect 12 ******
fx_12 tst.b d3
bne.s fx_12rts
add.w d4,trk_prevper(a5)
fx_12rts rts
; **************************************** Effect 00 ******
fx_00 tst.b d4 ;both fxqualifiers are 0s: no arpeggio
beq.s fx_00rts
move.l d3,d0
divu #3,d0
swap d0
subq.b #1,d0
bgt.s fx_arp2
blt.s fx_arp0
and.b #$0f,d4
bra.s fx_doarp
fx_arp0 lsr.b #4,d4
bra.s fx_doarp
fx_arp2 moveq #0,d4
fx_doarp: move.b (a5),d0
subq.b #1,d0 ;-1 to make it 0 - 127
add.b msng_playtransp(a4),d0 ;add play transpose
add.b trk_stransp(a5),d0 ;add instrument transpose
add.b d0,d4
move.l trk_periodtbl(a5),d1
beq.s fx_00rts
movea.l d1,a0
add.b d0,d0
move.w 0(a0,d0.w),d0 ;base note period
add.b d4,d4
sub.w 0(a0,d4.w),d0 ;calc difference from base note
move.w d0,trk_arpadjust(a5)
fx_00rts rts
; **************************************** Effect 04 ******
fx_14 move.b #6,trk_vibshift(a5)
bra.s vib_cont
fx_04 move.b #5,trk_vibshift(a5)
vib_cont tst.b d3
bne.s nonvib
move.b d4,d1
beq.s nonvib
and.w #$0f,d1
beq.s plr_chgvibspd
move.w d1,trk_vibrsz(a5)
plr_chgvibspd and.b #$f0,d4
beq.s nonvib
lsr.b #3,d4
and.b #$3e,d4
move.b d4,trk_vibrspd(a5)
nonvib move.b trk_vibroffs(a5),d0
lsr.b #2,d0
and.w #$1f,d0
moveq #0,d1
move.b sinetable(pc,d0.w),d0
ext.w d0
muls trk_vibrsz(a5),d0
move.b trk_vibshift(a5),d1
asr.w d1,d0
move.w d0,trk_vibradjust(a5)
move.b trk_vibrspd(a5),d0
add.b d0,trk_vibroffs(a5)
fx_04rts rts
sinetable: dc.b 0,25,49,71,90,106,117,125,127,125,117,106,90,71,49
dc.b 25,0,-25,-49,-71,-90,-106,-117,-125,-127,-125,-117
dc.b -106,-90,-71,-49,-25,0
; **************************************** Effect 06 ******
EVEN
fx_06: tst.b d3
bne.s fx_06nocnt0
btst #5,msng_flags(a4)
bne.s fx_04rts
fx_06nocnt0 bsr.s plr_volslide ;Volume slide
bra.s nonvib ;+ Vibrato
; **************************************** Effect 07 ******
fx_07 tst.b d3
bne.s nontre
move.b d4,d1
beq.s nontre
and.w #$0f,d1
beq.s plr_chgtrespd
move.w d1,trk_tremsz(a5)
plr_chgtrespd and.b #$f0,d4
beq.s nontre
lsr.b #2,d4
and.b #$3e,d4
move.b d4,trk_tremspd(a5)
nontre move.b trk_tremoffs(a5),d0
lsr.b #3,d0
and.w #$1f,d0
lea sinetable(pc),a0
move.b 0(a0,d0.w),d1
ext.w d1
muls trk_tremsz(a5),d1
asr.w #7,d1
move.b trk_tremspd(a5),d0
add.b d0,trk_tremoffs(a5)
add.b trk_prevvol(a5),d1
bpl.s tre_pos
moveq #0,d1
tre_pos cmp.b #64,d1
ble.s tre_no2hi
moveq #64,d1
tre_no2hi move.b d1,trk_tempvol(a5)
rts
; ********* VOLUME SLIDE FUNCTION *************************
plr_volslide move.b d4,d0
moveq #0,d1
move.b trk_prevvol(a5),d1 ;move previous vol to d1
and.b #$f0,d0
bne.s crescendo
sub.b d4,d1 ;sub from prev. vol
voltest0 bpl.s novolover64
moveq #0,d1 ;volumes under zero not accepted
bra.s novolover64
crescendo: lsr.b #4,d0
add.b d0,d1
voltest cmp.b #64,d1
ble.s novolover64
moveq #64,d1
novolover64 movea.l trk_audioaddr(a5),a0
movea.l ac_vol(a0),a0
move.b d1,(a0)
volsl_rts rts
; **************************************** Effect 0D/0A ***
fx_0a:
fx_0d: tst.b d3
bne.s plr_volslide
btst #5,msng_flags(a4)
beq.s plr_volslide
rts
; **************************************** Effect 05 ******
fx_05: tst.b d3
bne.s fx_05nocnt0
btst #5,msng_flags(a4)
bne.s fx_05rts
fx_05nocnt0 bsr.s plr_volslide
bra.s fx_03nocnt0
fx_05rts rts
; **************************************** Effect 1A ******
fx_1a tst.b d3
bne.s volsl_rts
move.b trk_prevvol(a5),d1
add.b d4,d1
bra.s voltest
; **************************************** Effect 1B ******
fx_1b tst.b d3
bne.s volsl_rts
move.b trk_prevvol(a5),d1
sub.b d4,d1
bra.s voltest0
; **************************************** Effect 03 ******
fx_03 tst.b d3
bne.s fx_03nocnt0
btst #5,msng_flags(a4)
bne.s fx_03rts
fx_03nocnt0 move.w trk_porttrgper(a5),d0 ;d0 = target period
beq.s fx_03rts
move.w trk_prevper(a5),d1 ;d1 = curr. period
move.b trk_prevportspd(a5),d4 ;get prev. speed
cmp.w d0,d1
bhi.s subper ;curr. period > target period
add.w d4,d1 ;add the period
cmp.w d0,d1
bge.s targreached
bra.s targnreach
subper: sub.w d4,d1 ;subtract
cmp.w d0,d1 ;compare current period to target period
bgt.s targnreach
targreached: move.w trk_porttrgper(a5),d1 ;eventually push target period
clr.w trk_porttrgper(a5) ;now we can forget everything
targnreach: move.w d1,trk_prevper(a5)
fx_03rts rts
; **************************************** Effect 13 ******
fx_13: cmp.b #3,d3
bge.s fx_13rts ;if counter < 3
neg.w d4
move.w d4,trk_vibradjust(a5) ;subtract effect qual...
fx_13rts rts
; **************************************** Effect 18 ******
fx_18 cmp.b d4,d3
bne.s fx_18rts
clr.b trk_prevvol(a5)
fx_18rts rts
; **************************************** Effect 1F ******
fx_1f move.b d4,d1
lsr.b #4,d4 ;note delay
beq.s nonotedelay
cmp.b d4,d3 ;compare to counter
blt.s fx_18rts ;tick not reached
bne.s nonotedelay
bra playfxnote ;trigger note
nonotedelay and.w #$0f,d1 ;retrig?
beq.s fx_18rts
moveq #0,d0
move.b d3,d0
divu d1,d0
swap d0 ;get modulo of counter/tick
tst.w d0
bne.s fx_18rts
bra playfxnote ;retrigger
; **************************************** Effect 0F ******
; see below...
; *********************************************************
; **** a separate routine for handling command 0F
fx_0f cmp.b #$f1,d4
bne.s no0ff1
cmp.b #3,d3
beq.s playfxnote
rts
no0ff1: cmp.b #$f2,d4
bne.s no0ff2
cmp.b #3,d3
beq.s playfxnote
rts
no0ff2: cmp.b #$f3,d4
bne.s no0ff3
move.b d3,d0
beq.s cF_rts
and.b #1,d0 ;is 2 or 4
bne.s cF_rts
playfxnote: moveq #0,d1
move.b trk_currnote(a5),d1 ;get note # of curr. note
beq.s cF_rts
move.b trk_noteoffcnt(a5),d0 ;get hold counter
bmi.s pfxn_nohold ;no hold, or hold over
add.b d3,d0 ;increase by counter val
bra.s pfxn_hold
pfxn_nohold move.b trk_inithold(a5),d0 ;get initial hold
bne.s pfxn_hold
st d0
pfxn_hold move.b d0,trk_noteoffcnt(a5)
movem.l a1/a3/d3/d6,-(sp)
moveq #0,d3
move.b trk_previnstr(a5),d3 ;and prev. sample #
movea.l trk_previnstra(a5),a3
bsr _PlayNote8
movem.l (sp)+,a1/a3/d3/d6
cF_rts rts
no0ff3: cmp.b #$f4,d4 ;triplet cmd 1
bne.s no0ff4
moveq #0,d0
move.b msng_tempo2(a4),d0
divu #3,d0
cmp.b d0,d3
beq.s playfxnote
rts
no0ff4 cmp.b #$f5,d4 ;triplet cmd 2
bne.s no0ff5
moveq #0,d0
move.b msng_tempo2(a4),d0
divu #3,d0
add.w d0,d0
cmp.b d0,d3
beq.s playfxnote
rts
no0ff5 cmp.b #$f8,d4 ;f8 = filter off
beq.s plr_filteroff
cmp.b #$f9,d4 ;f9 = filter on
bne.s cF_rts
bclr #1,$bfe001
bset #0,msng_flags(a4)
rts
plr_filteroff: bset #1,$bfe001
bclr #0,msng_flags(a4)
rts
_SetTempo: move.l _module8-DB(a6),d1
beq.s ST_x
movea.l d1,a0
movea.l mmd_songinfo(a0),a0
move.w d0,msng_deftempo(a0)
tst.w d0
ble.s ST_maxszcnt
cmp.w #9,d0
bls.s ST_nodef8tempo
ST_maxszcnt moveq #10,d0
ST_nodef8tempo add.b #9,d0
move.b d0,currchszcnt-DB+1(a6)
tst.b msng_flags(a0) ;test SLOWHQ compatibility flag
lea eightchsizes-10-DB(a6),a0
bmi.s ST_slowhq ;SLOWHQ set
tst.b _hq-DB(a6)
beq.s ST_nohq
move.b 10(a0,d0.w),d0 ;get buffersize / 4
add.w d0,d0 ;->buffersize / 2
bra.s ST_hqcont
ST_slowhq move.b 0(a0,d0.w),d0
add.w d0,d0
bra.s ST_hqcont
ST_nohq move.b 0(a0,d0.w),d0 ;get buffersize / 2
ST_hqcont move.w d0,currchsize2-DB(a6)
asl.w #3,d0 ;get buffersize * 4
move.w d0,currchsize-DB(a6)
ST_x rts
_Rem8chan: move.l a6,-(sp)
lea DB,a6
move.b eightrkon-DB(a6),d0
beq.s no8init
clr.b eightrkon-DB(a6)
move.w #1<<7,$dff09a
move.l prevaud-DB(a6),d0
beq.s no8init
move.l d0,a1
move.l 4,a6
moveq #7,d0
jsr -$a2(a6)
no8init move.l (sp)+,a6
rts
_End8Play: tst.b play8
beq.s noend8play
move.w #1<<7,$dff09a
move.w #$F,$dff096
clr.b play8
noend8play rts
; *************************************************************************
; *************************************************************************
; *********** P U B L I C F U N C T I O N S ***********
; *************************************************************************
; *************************************************************************
xdef _PlayModule8
xdef _InitPlayer8,_RemPlayer8,_StopPlayer8
xdef _ContModule8
; *************************************************************************
; InitModule8(a0 = module) -- extract expansion data etc.. from the module
; *************************************************************************
_InitModule8: movem.l a2-a3/a6/d2,-(sp)
lea DB,a6
move.l a0,d0
beq.w IM_exit ;0 => xit
lea holdvals-DB(a6),a2
movea.l mmd_songinfo(a0),a3
move.l mmd_expdata(a0),d0 ;expdata...
beq.s IM_clrhlddec ;none here
move.l d0,a1
move.l 4(a1),d0 ;exp_smp
beq.s IM_clrhlddec ;again.. nothing
move.l d0,a0 ;InstrExt...
move.w 8(a1),d2 ;# of entries
beq.s IM_clrhlddec
subq.w #1,d2 ;- 1 (for dbf)
move.w 10(a1),d0 ;entry size
IM_loop1 clr.b 63(a2) ;clear finetune
cmp.w #3,d0
ble.s IM_noftune
move.b 3(a0),63(a2)
IM_noftune clr.b 126(a2) ;clear flags
cmp.w #6,d0
blt.s IM_noflags
move.b 5(a0),126(a2) ;InstrExt.flags -> flags
bra.s IM_gotflags
IM_noflags cmp.w #1,inst_replen(a3)
bls.s IM_gotflags
bset #0,126(a2)
IM_gotflags move.b (a0),(a2)+ ;InstrExt.hold -> holdvals
adda.w d0,a0 ;ptr to next InstrExt
addq.l #8,a3 ;next instrument...
dbf d2,IM_loop1
bra.s IM_exit
IM_clrhlddec moveq #125,d0 ;no InstrExt => clear holdvals/decays
IM_loop2 clr.b (a2)+
dbf d0,IM_loop2
; -------- For (very old) MMDs, with no InstrExt, set flags/SSFLG_LOOP.
lea flags,a2
moveq #62,d0
IM_loop4 cmp.w #1,inst_replen(a3)
bls.s IM_noreptflg
bset #0,(a2)
IM_noreptflg addq.l #1,a2
addq.l #8,a3 ;next inst
dbf d0,IM_loop4
IM_exit movem.l (sp)+,a2-a3/a6/d2
rts
; *************************************************************************
; ContModule8(a0 = module) -- continue playing
; *************************************************************************
_ContModule8 bsr.w _End8Play
moveq #0,d0
bra.s contpoint8
; *************************************************************************
; PlayModule8(a0 = module) -- init and play a module
; *************************************************************************
_PlayModule8: st d0
contpoint8 move.l a6,-(sp)
lea DB,a6
movem.l a0/d0,-(sp)
bsr _InitModule8
movem.l (sp)+,a0/d0
IFNE AUDDEV
tst.b audiodevopen-DB(a6)
beq PM_end ;resource allocation failure
ENDC
move.l a0,d1
beq.w PM_end ;module failure
bsr.w _End8Play
clr.l _module8-DB(a6)
clr.l tmpvol-DB(a6)
move.w _modnum8,d1
beq.s PM_modfound
PM_nextmod tst.l mmd_expdata(a0)
beq.s PM_modfound
move.l mmd_expdata(a0),a1
tst.l (a1)
beq.s PM_modfound ;no more modules here!
move.l (a1),a0
subq.w #1,d1
bgt.s PM_nextmod
PM_modfound cmp.b #'T',3(a0)
bne.s PM_nomodT
move.b #'0',3(a0) ;change MCNT to MCN0
PM_nomodT movea.l mmd_songinfo(a0),a1 ;song
move.b msng_tempo2(a1),mmd_counter(a0) ;init counter
btst #0,msng_flags(a1)
bne.s PM_filon
bset #1,$bfe001
bra.s PM_filset
PM_filon bclr #1,$bfe001
PM_filset tst.b d0
beq.s PM_noclr
clr.l mmd_pline(a0)
clr.l rptline-DB(a6)
clr.w blkdelay-DB(a6)
; ---------- Set 'pblock' and 'pseq' to correct values...
PM_noclr cmp.b #'2',3(a0)
bcs.s PM_oldpbset
move.w mmd_psecnum(a0),d1
move.l a2,-(sp) ;need extra register
movea.l msng_sections(a1),a2
add.w d1,d1
move.w 0(a2,d1.w),d1 ;get sequence number
add.w d1,d1
add.w d1,d1
move.w d1,mmd_pseq(a0)
movea.l msng_pseqs(a1),a2
movea.l 0(a2,d1.w),a2 ;PlaySeq...
move.w mmd_pseqnum(a0),d1
add.w d1,d1
move.w 42(a2,d1.w),d1 ;and the correct block..
move.l (sp)+,a2
bra.s PM_setblk
PM_oldpbset move.w mmd_pseqnum(a0),d1
add.w #msng_playseq,d1
move.b 0(a1,d1.w),d1 ;get first playseq entry
ext.w d1
PM_setblk move.w d1,mmd_pblock(a0)
move.w #-1,mmd_pstate(a0)
move.l a0,_module8-DB(a6)
move.l mmd_expdata(a0),d0
beq.s PM_start
movea.l d0,a0
lea 36(a0),a0 ;track split mask
bsr.s _SetChMode
PM_start
IFNE FASTMEMPLAY
tst.w _fastmemplay8-DB(a6)
beq.s PM_nofmp
move.l a1,-(sp)
bsr.w _InitFastMemPlayer
movea.l (sp)+,a1
PM_nofmp
ENDC
bsr.s _Start8Play
PM_end move.l (sp)+,a6
rts
_SetChMode ;a0 = address of 4 UBYTEs
movem.l a2/d2,-(sp)
lea trksplit-DB(a6),a2
lea t07d+trk_split-DB(a6),a1
moveq #3,d0
moveq #0,d1
scm_loop lsr.b #1,d1
move.b (a0)+,d2
beq.s scm_split
moveq #0,d2
bra.s scm_nosplit
scm_split or.b #8,d1
st d2
scm_nosplit move.b d2,(a1)
move.b d2,4*TRACKDATASZ(a1)
lea TRACKDATASZ(a1),a1
move.b d2,(a2)+
dbf d0,scm_loop
move.w d1,chdmamask-DB(a6)
movem.l (sp)+,a2/d2
rts: rts
_Start8Play: ;d0 = pstate
move.l a6,-(sp)
lea DB,a1
lea _audiobuff,a0
move.w #1600-1,d1
clrbuffloop: clr.l (a0)+ ;clear track buffers
dbf d1,clrbuffloop
move.l _module8-DB(a1),d0
beq.s rts
move.l d0,a0
movea.l mmd_songinfo(a0),a0
move.w msng_deftempo(a0),d0 ;get deftempo
bsr.w _SetTempo
lea $dff000,a0
tst.b _hq-DB(a1)
bne.s s8p_hq
move.w #227,d1
bra.s s8p_nohq
s8p_hq move.w #124,d1
s8p_nohq move.w currchsize2-DB(a1),d0
move.l #_audiobuff,$a0(a0)
move.w d0,$a4(a0) ;set audio buffer sizes
move.w d1,$a6(a0)
tst.b trksplit+1-DB(a1)
beq.s 1$
move.l #_audiobuff+800,$b0(a0)
move.w d0,$b4(a0)
move.w d1,$b6(a0)
1$ tst.b trksplit+2-DB(a1)
beq.s 2$
move.l #_audiobuff+1600,$c0(a0)
move.w d0,$c4(a0)
move.w d1,$c6(a0)
2$ tst.b trksplit+3-DB(a1)
beq.s 3$
move.l #_audiobuff+2400,$d0(a0)
move.w d0,$d4(a0)
move.w d1,$d6(a0)
3$ moveq #64,d1
move.w d1,$a8(a0)
move.w d1,$b8(a0)
move.w d1,$c8(a0)
move.w d1,$d8(a0)
clr.b whichbuff-DB(a1)
movea.l 4.w,a6
move.w #$780,$9a(a0) ;audio interrupts off
tst.b play8-DB(a1)
bne.s 4$
movem.l a0/a1,-(sp)
moveq #7,d0 ;Audio channel 0 interrupt
lea audiointerrupt,a1
jsr -$a2(a6) ;SetIntVector()
movem.l (sp)+,a0/a1
4$ jsr -$78(a6) ;Disable()
lea track0hw-DB(a1),a1
moveq #7,d1
clrtrkloop clr.l (a1)
clr.w ac_per(a1)
adda.w #SIZE4TRKHW/4,a1
dbf d1,clrtrkloop
move.w #$F,$96(a0) ;audio DMA off
bsr.w _Wait1line ;wait until all stopped
lea DB,a1
st play8-DB(a1)
move.w #$8080,$9a(a0)
move.w chdmamask-DB(a1),d1
bset #15,d1
move.w d1,$96(a0)
movea.l 4.w,a6
jsr -$7e(a6) ;Enable()
move.l (sp)+,a6
rts
; *************************************************************************
; InitPlayer8() -- allocate interrupt, audio, serial port etc...
; *************************************************************************
_InitPlayer8: bsr.s _AudioInit
tst.l d0
bne.s IP_error
rts
IP_error bsr.s _RemPlayer8
moveq #-1,d0
rts
; *************************************************************************
; StopPlayer8() -- stop music
; *************************************************************************
_StopPlayer8: move.l _module8,d0
beq.s SP_nomod
movea.l d0,a0
clr.w mmd_pstate(a0)
clr.l _module8
SP_nomod bsr.w _End8Play
IFNE FASTMEMPLAY
bra.w _RemAudioInts
ELSEIF
rts
ENDC
; *************************************************************************
; RemPlayer8() -- free interrupt, audio, serial port etc..
; *************************************************************************
_RemPlayer8: bsr.s _StopPlayer8
; vvvvvvvvvvvvvvvv to _AudioRem
; *************************************************************************
_AudioRem: movem.l a5-a6,-(sp)
lea DB,a5
bsr.w _Rem8chan
IFNE AUDDEV
movea.l 4,a6
tst.b audiodevopen-DB(a5)
beq.s rem2
clr.b audiodevopen-DB(a5)
move.w #$000f,$dff096 ;stop audio DMA
; +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ close audio.device
lea allocreq-DB(a5),a1
jsr -$1c2(a6) ;CloseDevice()
rem2: moveq #0,d0
move.b sigbitnum-DB(a5),d0
bmi.s rem3
; +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ free signal bit
jsr -$150(a6) ;FreeSignal()
st sigbitnum-DB(a5)
ENDC
rem3: movem.l (sp)+,a5-a6
rts
_AudioInit: movem.l a4/a6/d2-d3,-(sp)
lea DB,a4
movea.l 4.w,a6
IFNE AUDDEV
moveq #0,d2
; +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ alloc signal bit
moveq #1,d2
moveq #-1,d0
jsr -$14a(a6) ;AllocSignal()
tst.b d0
bmi.w initerr
move.b d0,sigbitnum-DB(a4)
; +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ prepare IORequest
lea allocport-DB(a4),a1
move.b d0,15(a1) ;set mp_SigBit
move.l a1,-(sp)
suba.l a1,a1
jsr -$126(a6) ;FindTask(0)
move.l (sp)+,a1
move.l d0,16(a1) ;set mp_SigTask
lea reqlist-DB(a4),a0
move.l a0,(a0) ;NEWLIST begins...
addq.l #4,(a0)
clr.l 4(a0)
move.l a0,8(a0) ;NEWLIST ends...
; +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ open audio.device
moveq #2,d2
lea allocreq-DB(a4),a1
lea audiodevname-DB(a4),a0
moveq #0,d0
moveq #0,d1
jsr -$1bc(a6) ;OpenDevice()
tst.b d0
bne.w initerr
st.b audiodevopen-DB(a4)
ENDC
move.w #$0780,$dff09a
bsr.s _InitPlayRoutine
st eightrkon-DB(a4)
moveq #0,d0
initret: movem.l (sp)+,a4/a6/d2-d3
rts
initerr: move.l d2,d0
bra.s initret
_InitPlayRoutine
lea trackdata8,a0
movea.l (a0)+,a1
move.l #track0hw,d0
moveq #SIZE4TRKHW/4,d1
move.l d0,trk_audioaddr(a1)
add.l d1,d0
movea.l (a0)+,a1
move.l d0,trk_audioaddr(a1)
add.l d1,d0
move.l #fmpstructs,trk_fmp(a1)
movea.l (a0)+,a1
move.l d0,trk_audioaddr(a1)
add.l d1,d0
move.l #fmpstructs+fmp_sizeof,trk_fmp(a1)
movea.l (a0)+,a1
move.l d0,trk_audioaddr(a1)
add.l d1,d0
move.l #fmpstructs+fmp_sizeof*2,trk_fmp(a1)
movea.l (a0)+,a1
move.l d0,trk_audioaddr(a1)
add.l d1,d0
movea.l (a0)+,a1
move.l d0,trk_audioaddr(a1)
add.l d1,d0
movea.l (a0)+,a1
move.l d0,trk_audioaddr(a1)
add.l d1,d0
movea.l (a0)+,a1
move.l d0,trk_audioaddr(a1)
lea -32(a0),a0
moveq #7,d0
2$ movea.l (a0)+,a1
st trk_tempvol(a1)
dbf d0,2$
rts
DATA
XDEF _hq
DB: ;Data base pointer
IFNE AUDDEV
sigbitnum dc.b -1
audiodevopen dc.b 0
allocm dc.b $F,0
ENDC
chdmamask dc.w 0
trksplit dc.b 0,0,0,0
even
IFNE AUDDEV
allocport dc.l 0,0 ;succ, pred
dc.b 4,0 ;NT_MSGPORT
dc.l 0 ;name
dc.b 0,0 ;flags = PA_SIGNAL
dc.l 0 ;task
reqlist dc.l 0,0,0 ;list head, tail and tailpred
dc.b 5,0
allocreq dc.l 0,0
dc.b 0,127 ;NT_UNKNOWN, use maximum priority (127)
dc.l 0,allocport ;name, replyport
dc.w 68 ;length
dc.l 0 ;io_Device
dc.l 0 ;io_Unit
dc.w 0 ;io_Command
dc.b 0,0 ;io_Flags, io_Error
dc.w 0 ;ioa_AllocKey
dc.l allocm ;ioa_Data
dc.l 1 ;ioa_Length
dc.w 0,0,0 ;ioa_Period, Volume, Cycles
dc.w 0,0,0,0,0,0,0,0,0,0 ;ioa_WriteMsg
audiodevname dc.b 'audio.device',0
ENDC
even
zerodata dc.w 0
whichbuff dc.w 0
track0hw dc.l 0,0,tmpvol,0,0
dc.w $0001,$df,$f0a0
dc.l 0
track1hw dc.l 0,0,tmpvol+1,0,0
dc.w $0002,$df,$f0b0
dc.l fmpstructs
track2hw dc.l 0,0,tmpvol+2,0,0
dc.w $0004,$df,$f0c0
dc.l fmpstructs+fmp_sizeof
track3hw dc.l 0,0,tmpvol+3,0,0
dc.w $0008,$df,$f0d0
dc.l fmpstructs+2*fmp_sizeof
track4hw dc.l 0,0,tmpvol,0,0
dc.w 0,0,0
dc.l 0
track5hw dc.l 0,0,tmpvol+1,0,0
dc.w 0,0,0
dc.l 0
track6hw dc.l 0,0,tmpvol+2,0,0
dc.w 0,0,0
dc.l 0
track7hw dc.l 0,0,tmpvol+3,0,0
dc.w 0,0,0
dc.l 0
SIZE4TRKHW equ 4*$1E
tmpvol dc.b 0,0,0,0
audintname dc.b 'OctaMED AudioInterrupt',0
even
audiointerrupt dc.w 0,0,0,0,0
dc.l audintname,_audiobuff,_IntHandler8
prevaud dc.l 0
play8 dc.b 0
eightrkon dc.b 0
intonmsk dc.w 0
dmaonmsk dc.w 0
; TRACK-data structures
t07d ds.b 8*TRACKDATASZ
; Build pointer table. This works on Devpac assembler, other assemblers
; may need modifications.
trackdata8
TRKCOUNT SET 0
REPT 8
dc.l t07d+TRKCOUNT
TRKCOUNT SET TRKCOUNT+TRACKDATASZ
ENDR
blkdelay dc.w 0 ;block delay (PT PatternDelay)
eightchsizes dc.b 110,120,130,140,150,160,170,180,190,200
dc.b 101,110,119,128,137,146,156,165,174,183 ;HQ sizes
currchsize dc.w 0 ;<< 3
currchsize2 dc.w 0
currchszcnt dc.w 0
nextblock dc.b 0 ;\ DON'T SEPARATE
nxtnoclrln dc.b 0 ;/
numtracks dc.w 0
numlines dc.w 0
numpages dc.w 0
nextblockline dc.w 0
rptline dc.w 0
rptcounter dc.w 0
_module8 dc.l 0
fxplineblk dc.l 0
_hq dc.b 1
EVEN
IFNE FASTMEMPLAY
XDEF _fastmemplay8,_fmp_buffsize8
_use_fastmem dc.w 0
_fmp_buffsize8 dc.w 64 ;must be divisible by 4!
_fastmemplay8 dc.w 0
; Fastmemplay interrupt structures
fmpintname dc.b 'OctaMED FastMemPlay Int',0
even
fmpinterrupt1 dc.w 0,0,0,0,0
dc.l fmpintname,fmpstructs,_FmpIntHandler
fmpinterrupt2 dc.w 0,0,0,0,0
dc.l fmpintname,fmpstructs+fmp_sizeof,_FmpIntHandler
fmpinterrupt3 dc.w 0,0,0,0,0
dc.l fmpintname,fmpstructs+2*fmp_sizeof,_FmpIntHandler
ENDC
holdvals ds.b 63
finetunes ds.b 63
flags ds.b 63
EVEN
IFNE IFFMOCT
dc.w 3424,3232,3048,2880,2712,2560,2416,2280,2152,2032,1920,1812
dc.w 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906
ENDC
per0 dc.w 856,808,762,720,678,640,604,570,538,508,480,453
dc.w 428,404,381,360,339,320,302,285,269,254,240,226
dc.w 214,202,190,180,170,160,151,143,135,127,120,113
dc.w 214,202,190,180,170,160,151,143,135,127,120,113
dc.w 214,202,190,180,170,160,151,143,135,127,120,113
dc.w 214,202,190,180,170,160,151,143,135,127,120,113
IFNE IFFMOCT
dc.w 3400,3209,3029,2859,2699,2547,2404,2269,2142,2022,1908,1801
dc.w 1700,1605,1515,1430,1349,1274,1202,1135,1071,1011,954,901
ENDC
per1 dc.w 850,802,757,715,674,637,601,567,535,505,477,450
dc.w 425,401,379,357,337,318,300,284,268,253,239,225
dc.w 213,201,189,179,169,159,150,142,134,126,119,113
dc.w 213,201,189,179,169,159,150,142,134,126,119,113
dc.w 213,201,189,179,169,159,150,142,134,126,119,113
dc.w 213,201,189,179,169,159,150,142,134,126,119,113
IFNE IFFMOCT
dc.w 3376,3187,3008,2839,2680,2529,2387,2253,2127,2007,1895,1788
dc.w 1688,1593,1504,1419,1340,1265,1194,1127,1063,1004,947,894
ENDC
per2 dc.w 844,796,752,709,670,632,597,563,532,502,474,447
dc.w 422,398,376,355,335,316,298,282,266,251,237,224
dc.w 211,199,188,177,167,158,149,141,133,125,118,112
dc.w 211,199,188,177,167,158,149,141,133,125,118,112
dc.w 211,199,188,177,167,158,149,141,133,125,118,112
dc.w 211,199,188,177,167,158,149,141,133,125,118,112
IFNE IFFMOCT
dc.w 3352,3164,2986,2819,2660,2511,2370,2237,2112,1993,1881,1776
dc.w 1676,1582,1493,1409,1330,1256,1185,1119,1056,997,941,888
ENDC
per3 dc.w 838,791,746,704,665,628,592,559,528,498,470,444
dc.w 419,395,373,352,332,314,296,280,264,249,235,222
dc.w 209,198,187,176,166,157,148,140,132,125,118,111
dc.w 209,198,187,176,166,157,148,140,132,125,118,111
dc.w 209,198,187,176,166,157,148,140,132,125,118,111
dc.w 209,198,187,176,166,157,148,140,132,125,118,111
IFNE IFFMOCT
dc.w 3328,3141,2965,2799,2641,2493,2353,2221,2097,1979,1868,1763
dc.w 1664,1571,1482,1399,1321,1247,1177,1111,1048,989,934,881
ENDC
per4 dc.w 832,785,741,699,660,623,588,555,524,495,467,441
dc.w 416,392,370,350,330,312,294,278,262,247,233,220
dc.w 208,196,185,175,165,156,147,139,131,124,117,110
dc.w 208,196,185,175,165,156,147,139,131,124,117,110
dc.w 208,196,185,175,165,156,147,139,131,124,117,110
dc.w 208,196,185,175,165,156,147,139,131,124,117,110
IFNE IFFMOCT
dc.w 3304,3119,2944,2778,2622,2475,2336,2205,2081,1965,1854,1750
dc.w 1652,1559,1472,1389,1311,1238,1168,1103,1041,982,927,875
ENDC
per5 dc.w 826,779,736,694,655,619,584,551,520,491,463,437
dc.w 413,390,368,347,328,309,292,276,260,245,232,219
dc.w 206,195,184,174,164,155,146,138,130,123,116,109
dc.w 206,195,184,174,164,155,146,138,130,123,116,109
dc.w 206,195,184,174,164,155,146,138,130,123,116,109
dc.w 206,195,184,174,164,155,146,138,130,123,116,109
IFNE IFFMOCT
dc.w 3280,3096,2922,2758,2603,2457,2319,2189,2066,1950,1841,1738
dc.w 1640,1548,1461,1379,1302,1229,1160,1095,1033,975,920,869
ENDC
per6 dc.w 820,774,730,689,651,614,580,547,516,487,460,434
dc.w 410,387,365,345,325,307,290,274,258,244,230,217
dc.w 205,193,183,172,163,154,145,137,129,122,115,109
dc.w 205,193,183,172,163,154,145,137,129,122,115,109
dc.w 205,193,183,172,163,154,145,137,129,122,115,109
dc.w 205,193,183,172,163,154,145,137,129,122,115,109
IFNE IFFMOCT
dc.w 3256,3073,2901,2738,2584,2439,2302,2173,2051,1936,1827,1725
dc.w 1628,1537,1450,1369,1292,1220,1151,1087,1026,968,914,862
ENDC
per7 dc.w 814,768,725,684,646,610,575,543,513,484,457,431
dc.w 407,384,363,342,323,305,288,272,256,242,228,216
dc.w 204,192,181,171,161,152,144,136,128,121,114,108
dc.w 204,192,181,171,161,152,144,136,128,121,114,108
dc.w 204,192,181,171,161,152,144,136,128,121,114,108
dc.w 204,192,181,171,161,152,144,136,128,121,114,108
IFNE IFFMOCT
dc.w 3628,3424,3232,3051,2880,2718,2565,2421,2285,2157,2036,1922
dc.w 1814,1712,1616,1525,1440,1359,1283,1211,1143,1079,1018,961
ENDC
per_8 dc.w 907,856,808,762,720,678,640,604,570,538,508,480
dc.w 453,428,404,381,360,339,320,302,285,269,254,240
dc.w 226,214,202,190,180,170,160,151,143,135,127,120
dc.w 226,214,202,190,180,170,160,151,143,135,127,120
dc.w 226,214,202,190,180,170,160,151,143,135,127,120
dc.w 226,214,202,190,180,170,160,151,143,135,127,120
IFNE IFFMOCT
dc.w 3588,3387,3197,3017,2848,2688,2537,2395,2260,2133,2014,1901
dc.w 1794,1693,1598,1509,1424,1344,1269,1197,1130,1067,1007,950
ENDC
per_7 dc.w 900,850,802,757,715,675,636,601,567,535,505,477
dc.w 450,425,401,379,357,337,318,300,284,268,253,238
dc.w 225,212,200,189,179,169,159,150,142,134,126,119
dc.w 225,212,200,189,179,169,159,150,142,134,126,119
dc.w 225,212,200,189,179,169,159,150,142,134,126,119
dc.w 225,212,200,189,179,169,159,150,142,134,126,119
IFNE IFFMOCT
dc.w 3576,3375,3186,3007,2838,2679,2529,2387,2253,2126,2007,1894
dc.w 1788,1688,1593,1504,1419,1339,1264,1193,1126,1063,1003,947
ENDC
per_6 dc.w 894,844,796,752,709,670,632,597,563,532,502,474
dc.w 447,422,398,376,355,335,316,298,282,266,251,237
dc.w 223,211,199,188,177,167,158,149,141,133,125,118
dc.w 223,211,199,188,177,167,158,149,141,133,125,118
dc.w 223,211,199,188,177,167,158,149,141,133,125,118
dc.w 223,211,199,188,177,167,158,149,141,133,125,118
IFNE IFFMOCT
dc.w 3548,3349,3161,2984,2816,2658,2509,2368,2235,2110,1991,1879
dc.w 1774,1674,1580,1492,1408,1329,1254,1184,1118,1055,996,940
ENDC
per_5 dc.w 887,838,791,746,704,665,628,592,559,528,498,470
dc.w 444,419,395,373,352,332,314,296,280,264,249,235
dc.w 222,209,198,187,176,166,157,148,140,132,125,118
dc.w 222,209,198,187,176,166,157,148,140,132,125,118
dc.w 222,209,198,187,176,166,157,148,140,132,125,118
dc.w 222,209,198,187,176,166,157,148,140,132,125,118
IFNE IFFMOCT
dc.w 3524,3326,3140,2963,2797,2640,2492,2352,2220,2095,1978,1867
dc.w 1762,1663,1570,1482,1399,1320,1246,1176,1110,1048,989,933
ENDC
per_4 dc.w 881,832,785,741,699,660,623,588,555,524,494,467
dc.w 441,416,392,370,350,330,312,294,278,262,247,233
dc.w 220,208,196,185,175,165,156,147,139,131,123,117
dc.w 220,208,196,185,175,165,156,147,139,131,123,117
dc.w 220,208,196,185,175,165,156,147,139,131,123,117
dc.w 220,208,196,185,175,165,156,147,139,131,123,117
IFNE IFFMOCT
dc.w 3500,3304,3118,2943,2778,2622,2475,2336,2205,2081,1964,1854
dc.w 1750,1652,1559,1472,1389,1311,1237,1168,1102,1041,982,927
ENDC
per_3 dc.w 875,826,779,736,694,655,619,584,551,520,491,463
dc.w 437,413,390,368,347,328,309,292,276,260,245,232
dc.w 219,206,195,184,174,164,155,146,138,130,123,116
dc.w 219,206,195,184,174,164,155,146,138,130,123,116
dc.w 219,206,195,184,174,164,155,146,138,130,123,116
dc.w 219,206,195,184,174,164,155,146,138,130,123,116
IFNE IFFMOCT
dc.w 3472,3277,3093,2920,2756,2601,2455,2317,2187,2064,1949,1839
dc.w 1736,1639,1547,1460,1378,1301,1228,1159,1094,1032,974,920
ENDC
per_2 dc.w 868,820,774,730,689,651,614,580,547,516,487,460
dc.w 434,410,387,365,345,325,307,290,274,258,244,230
dc.w 217,205,193,183,172,163,154,145,137,129,122,115
dc.w 217,205,193,183,172,163,154,145,137,129,122,115
dc.w 217,205,193,183,172,163,154,145,137,129,122,115
dc.w 217,205,193,183,172,163,154,145,137,129,122,115
IFNE IFFMOCT
dc.w 3448,3254,3072,2899,2737,2583,2438,2301,2172,2050,1935,1827
dc.w 1724,1627,1536,1450,1368,1292,1219,1151,1086,1025,968,913
ENDC
per_1 dc.w 862,814,768,725,684,646,610,575,543,513,484,457
dc.w 431,407,384,363,342,323,305,288,272,256,242,228
dc.w 216,203,192,181,171,161,152,144,136,128,121,114
dc.w 216,203,192,181,171,161,152,144,136,128,121,114
dc.w 216,203,192,181,171,161,152,144,136,128,121,114
dc.w 216,203,192,181,171,161,152,144,136,128,121,114
_periodtable
dc.l per_8,per_7,per_6,per_5,per_4,per_3,per_2,per_1,per0
dc.l per1,per2,per3,per4,per5,per6,per7
IFND __G2
section "datachip",bss,chip ;for A68k
ENDC
IFD __G2
section "datachip",bss_c ;this is for Devpac 2
ENDC
XDEF _modnum8
_audiobuff: ds.w 400*8
_fmpaudiobuff ds.w 2400
IFNE FASTMEMPLAY
ENDC
_modnum8: ds.w 1
_chipzero: ds.w 1
IFNE FASTMEMPLAY
BSS
fmpstructs ds.b fmp_sizeof*3
ENDC
END